package com.bjx.file.service.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import com.bjx.common.core.domain.bo.FileInfoBO;
import com.bjx.common.core.exception.BJXException;
import com.bjx.common.core.util.FileUtils;
import com.bjx.file.config.MinioConfig;
import com.bjx.file.domain.vo.FileVO;
import com.bjx.file.service.FileService;
import io.minio.*;
import io.minio.http.Method;
import lombok.extern.slf4j.Slf4j;
import okhttp3.Headers;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;

/**
 * @desc: 文件服务实现类
 * @author: liushuai
 * @date: 2023/5/15 14:58
 */
@Slf4j
@Service
public class FileServiceImpl implements FileService {
    @Resource
    private MinioConfig minioConfig;

    @Resource
    private MinioClient client;

    @Override
    public FileVO upload(MultipartFile file, Boolean open) {
        InputStream inputStream = null;
        String bucketName = open ? minioConfig.getPublicBucketName() : minioConfig.getBucketName();
        try {
            //对上传的文件进行重命名,防止文件名称冲突
            FileInfoBO fileInfoBO = FileUtils.renameFileName(file.getName());
            inputStream = file.getInputStream();
            //组装上传参数
            PutObjectArgs args = PutObjectArgs.builder()
                    .bucket(bucketName)
                    .object(fileInfoBO.getSaveUrl())
                    .stream(inputStream, file.getSize(), -1)
                    .contentType(file.getContentType())
                    .build();
            //上传到minio
            client.putObject(args);
            return FileVO.builder()
                    .fileType(fileInfoBO.getFileType())
                    .originalFileName(file.getName())
                    .saveFileName(fileInfoBO.getSaveFileName())
                    .saveUrl(fileInfoBO.getSaveUrl())
                    .build();
        } catch (Exception e) {
            log.error("上传文件失败文件名称:{}", file.getName());
            log.error("上传文件失败:{}", e);
            throw new BJXException("上传文件失败");
        } finally {
            IoUtil.close(inputStream);
        }
    }

    @Override
    public FileVO preview(String url, Boolean open) {
        String previewUrl = null;
        try {
            if (open) {
                //开放文件
                previewUrl = client.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                        .bucket(minioConfig.getPublicBucketName())
                        .object(url)
                        .method(Method.GET)
                        .build());
            } else {
                //加密文件
                previewUrl = client.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                        .bucket(minioConfig.getBucketName())
                        .object(url)
                        .method(Method.GET)
                        .expiry(minioConfig.getExpiry())
                        .build());
            }
            return FileVO.builder()
                    .saveUrl(url)
                    .viewUrl(previewUrl)
                    .build();
        } catch (Exception e) {
            log.error("文件预览失败url:{}", url);
            log.error("文件预览失败:{}", e);
            throw new BJXException("文件预览失败");
        }
    }

    @Override
    public void download(HttpServletResponse httpServletResponse, String url, Boolean open) {
        ServletOutputStream os = null;
        GetObjectResponse object = null;
        String bucketName = open ? minioConfig.getPublicBucketName() : minioConfig.getBucketName();
        try {
            os = httpServletResponse.getOutputStream();
            object = client.getObject(GetObjectArgs.builder()
                    .bucket(bucketName)
                    .object(url)
                    .build());
            Headers headers = object.headers();
            httpServletResponse.setContentType(headers.get("content-type"));
            httpServletResponse.setContentLength(Integer.valueOf(headers.get("Content-Length")));
            httpServletResponse.setHeader("Content-Disposition", String.format("attachment;filename=%s", FileUtil.getName(url)));
            byte[] b = new byte[1024 * 8];
            int leg = 0;
            while ((leg = object.read(b)) != -1) {
                os.write(b, 0, leg);
            }
            os.flush();
        } catch (Exception e) {
            log.error("文件下载失败url:{}", url);
            log.error("文件下载失败", e);
            throw new BJXException("文件下载失败");
        } finally {
            IoUtil.close(os);
        }
    }

    @Override
    public void delete(String url, Boolean open) {
        String bucketName = open ? minioConfig.getPublicBucketName() : minioConfig.getBucketName();
        try {
            client.removeObject(RemoveObjectArgs.builder()
                    .bucket(bucketName)
                    .object(url)
                    .build());
        } catch (Exception e) {
            log.error("删除文件失败url:{}", url);
            log.error("删除文件失败:{}", e);
            throw new BJXException("删除文件失败");
        }
    }
}
